package com.fhzn.auth.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fhzn.auth.constant.Constants;
import com.fhzn.auth.entity.*;
import com.fhzn.auth.enums.AdminSignEnum;
import com.fhzn.auth.enums.WebResponseEnum;
import com.fhzn.auth.mapper.*;
import com.fhzn.auth.service.OperatorLogService;
import com.fhzn.auth.service.RoleResourceService;
import com.fhzn.auth.service.RoleService;
import com.fhzn.auth.service.UserService;
import com.fhzn.auth.tools.AuthUtil;
import com.fhzn.auth.web.converter.RoleConverter;
import com.fhzn.auth.web.request.RoleOpRequest;
import com.fhzn.auth.web.request.RoleQueryRequest;
import com.fhzn.auth.web.request.RoleResourceRequest;
import com.fhzn.auth.web.request.RoleUserRequest;
import com.fhzn.auth.web.vo.RoleVO;
import com.fhzn.commons.toolkit.exception.BuzException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author 老顾
 * @apiNote
 * @since 2023/12/25
 */
@Service
@AllArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    private final RoleMapper roleMapper;
    private final UserMapper userMapper;
    private final UserRoleMapper userRoleMapper;
    private final OperatorLogService operatorLogService;
    private final UserService userService;
    private final ResourceMapper resourceMapper;
    private final RoleResourceMapper roleResourceMapper;
    private final RoleResourceService roleResourceService;


    @Override
    public boolean isSuperAdminOrAdmin(String handler, String appCode) {
        List<Role> roles = roleMapper.findRolesByNickname(handler);
        return AuthUtil.isSuperAdmin(roles) || AuthUtil.isAdmin(roles, appCode);
    }

    @Override
    public Page<Role> roleWithPage(RoleQueryRequest request) {
        request.setAppCode(request.getInvokeAppName());
        request.checkParams();
        request.rewriteParams();
        request.getOffset();

        Page<Role> roles = roleMapper.getRolesByList(request);

        if (Objects.nonNull(roles) && request.getIsCalculateAssignedUser()) {
            List<Integer> roleIdList = roles.getRecords().stream().map(Role::getId).collect(Collectors.toList());
            List<Map<String, Object>> roleUserList = userRoleMapper.queryCountOfAssignedUserByRoleIdList(roleIdList);

            // 将 roleUserList 转换为 Map，以便后续通过 roleId 进行快速查找
            Map<Integer, Map<String, Object>> roleUserMap = Maps.newHashMap();
            for (Map<String, Object> roleUser : roleUserList) {
                Integer roleId = Integer.parseInt(String.valueOf(roleUser.get("roleId")));
                roleUserMap.put(roleId, roleUser);
            }

            // 将查询结果合并到 roles 中
            for (Role role : roles.getRecords()) {
                Integer roleId = role.getId();
                if (roleUserMap.containsKey(roleId)) {
                    Map<String, Object> roleUser = roleUserMap.get(roleId);
                    role.setCountOfAssignedUser(Integer.parseInt(String.valueOf(roleUser.get("count"))));
                }
            }
        }

        return roles;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RoleVO add(RoleOpRequest request) {
        request.checkBaseParams();
        request.setAppCode(request.getInvokeAppName());
        request.checkAdd();
        Role role = request.addGenServiceParam();
        // 新增角色
        List<Role> handlerRoles = roleMapper.findRolesByNickname(request.getHandler());
        this.preCheck(role, handlerRoles);
        roleMapper.insert(role);
        // 记录操作日志
        operatorLogService.operatorLog(request.getHandler(), Constants.ROLE_SECTION,
                Constants.ROLE_ADD_METHOD, String.valueOf(role.getId()), null,
                roleMapper.getRoleByCode(request.getCode(), request.getInvokeAppName()), Constants.AUTH_APP_CODE);
        return RoleConverter.fromRole(role);
    }

    @Override
    public String update(RoleOpRequest request) {
        request.checkBaseParams();
        request.setAppCode(request.getInvokeAppName());
        request.checkUpdate();
        Role roleBefore = roleMapper.selectById(request.getId());
        // 角色编辑
        this.updateRole(request.genServiceParam(), request.getHandler());
        // 记录操作日志
        operatorLogService.operatorLog(request.getHandler(), Constants.ROLE_SECTION,
                Constants.ROLE_UPDATE_METHOD, String.valueOf(request.getId()), roleBefore,
                roleMapper.selectById(request.getId()), Constants.AUTH_APP_CODE);

        return WebResponseEnum.SUCCESS.getMessage();
    }

    @Override
    public Page<User> pageQueryAssignedUsers(RoleQueryRequest request) {
        request.setAppCode(request.getInvokeAppName());
        request.checkBaseParams();
        request.getOffset();
        Role role = roleMapper.getRoleByCode(request.getCode(), request.getInvokeAppName());
        if (null == role) {
            return Page.of(0, 0);
        }
        request.setId(role.getId());
        List<UserRole> userRoleList = userRoleMapper.pageQueryUserListByRoleId(request);
        if (CollectionUtils.isEmpty(userRoleList)) {
            return Page.of(0, 0);
        }
        List<Integer> userIdList = userRoleList.stream().map(UserRole::getUserId).collect(Collectors.toList());
        return userMapper.pageQueryUserListByRoleId(userIdList, request);
    }

    @Override
    public String assignUsers(RoleUserRequest request) {
        request.checkBaseParams();
        request.setAppCode(request.getInvokeAppName());
        request.setCode(request.getCode());
        request.setUsers(String.join(",", request.getUserList()));
        request.checkBaseParams();
        if (StringUtils.isEmpty(request.getUsers()) || StringUtils.isEmpty(request.getCode())) {
            throw new BuzException("请求错误");
        }
        List<String> userNames = Lists.newArrayList(request.getUsers().split(","));
        userService.configureUsersRole(userNames, request.getCode(), request.getHandler(), request.getType(), request.getAppCode());
        return WebResponseEnum.SUCCESS.getMessage();
    }

    @Override
    public RoleVO queryOne(RoleQueryRequest request) {
        request.checkId();
        Role role = roleMapper.selectById(request.getId());
        return RoleConverter.fromRole(role);
    }

    @Override
    public Page<Resource> pageQueryAssignedResources(RoleQueryRequest request) {
        request.checkId();
        Role role = roleMapper.selectById(request.getId());
        List<Role> canAppointRoles = roleMapper.findCanAppointRoles(Collections.singletonList(request.getId()));
        role.setCanAppointRoles(canAppointRoles);

        // 根据角色id查询角色资源列表
        List<RoleResource> roleResources = roleResourceMapper.findRoleResourceByRoleId(request.getId());

        // 获取资源id列表
        List<Integer> resourceIds = roleResources.stream().map(RoleResource::getResourceId).collect(Collectors.toList());

        return resourceMapper.pageQueryResourcesByRoleId(resourceIds, request);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String configResources(RoleResourceRequest request) {
        request.checkBaseParams();
        request.setAppCode(request.getInvokeAppName());
        request.setId(request.getId());
        request.setResources(request.getResourceList().stream().map(String::valueOf).collect(Collectors.joining(",")));
        request.checkBaseParams();

        // 根据角色id查询角色资源列表
        List<RoleResource> roleResources = roleResourceMapper.findRoleResourceByRoleId(request.getId());

        // 获取资源id列表
        List<Integer> resourceIds = roleResources.stream().map(RoleResource::getResourceId).collect(Collectors.toList());
        Role role = roleMapper.selectById(request.getId());

        if (AuthUtil.isAdminOrSuperAdmin(role)) {
            throw new BuzException("管理员无需配置下属资源");
        }
        if (isSuperAdminOrAdmin(request.getHandler(), role.getAppCode())) {
            if (isSuperAdminOrAdmin(request.getHandler(), role.getAppCode())) {
                roleResourceMapper.deleteByRoleId(request.getId());
                if (CollectionUtils.isNotEmpty(roleResources)) {
                    roleResourceService.saveBatch(request.genRoleResourceList());
                }
            }
            // 记录操作日志
            operatorLogService.operatorLog(request.getHandler(), Constants.ROLE_SECTION,
                    Constants.ROLE_CONFIG_RESOURCES_ASSIGN, String.valueOf(request.getId()),
                    StringUtils.join(resourceIds, ","), request.getResources(), Constants.AUTH_APP_CODE);
            return WebResponseEnum.SUCCESS.getMessage();
        } else {
            throw new BuzException("无操作权限");
        }

    }

    @Override
    public boolean isSuperAdmin(String handler) {
        return AuthUtil.isSuperAdmin(findRolesByNickname(handler));
    }

    @Override
    public String export(RoleOpRequest request) {
        return null;
    }

    /**
     * 根据用户昵称查询角色
     *
     * @param nickName 用户昵称
     * @return 角色列表
     */
    private List<Role> findRolesByNickname(String nickName) {
        return roleMapper.findRolesByNickname(nickName);
    }

    private void updateRole(Role role, String handler) {
        Role roleInfo = roleMapper.selectById(role.getId());
        if (AuthUtil.isSuperAdmin(roleInfo)) {
            throw new BuzException("不能修改超级管理员角色");
        }
        List<Role> handlerRoles = roleMapper.findRolesByNickname(handler);
        if (AuthUtil.isAdminOrSuperAdmin(handlerRoles, roleInfo.getAppCode())) {
            // 应用管理员角色只有超管能修改
            if (AuthUtil.isAdmin(roleInfo) && !AuthUtil.isSuperAdmin(handlerRoles)) {
                throw new BuzException("无操作权限");
            }
            if (AuthUtil.isAdmin(role) && !AuthUtil.isSuperAdmin(handlerRoles)) {
                throw new BuzException("无操作权限");
            }
            roleMapper.updateById(role);
        } else {
            throw new BuzException("无操作权限");
        }
    }

    /**
     * 添加角色前提前校验
     *
     * @param role         角色
     * @param handlerRoles 角色列表
     */
    private void preCheck(Role role, List<Role> handlerRoles) {
        // wups系统里面只有系统管理员和超级管理员才能创建角色
        if (Constants.AUTH_APP_CODE.equals(role.getAppCode()) && !AuthUtil.isAdminOrSuperAdmin(handlerRoles, role.getAppCode())) {
            throw new BuzException("无操作权限");
        }
        // 不能创建超级管理员
        if (AdminSignEnum.SUPERADMIN.getSign().equals(role.getSign())) {
            throw new BuzException("不能创建超级管理员角色");
        }
        // 非超级管理员不能创建应用管理员
        if (AuthUtil.isAdmin(role) && !AuthUtil.isSuperAdmin(handlerRoles)) {
            throw new BuzException("无权限操作");
        }
        // 不能创建权限系统的应用管理员
        if (AdminSignEnum.ADMIN.getSign().equals(role.getSign()) && Constants.AUTH_APP_CODE.equals(role.getAppCode())) {
            throw new BuzException("无需创建权限系统应用管理员");
        }
        // 一个应用下只能有一个管理员角色
        if (AdminSignEnum.ADMIN.getSign().equals(role.getSign())) {
            Long count = roleMapper.queryAppAdminCount(role.getAppCode(), AdminSignEnum.ADMIN.getSign());
            if (count > 0) {
                throw new BuzException("该应用下已有管理员角色,无需创建");
            }
        }
    }
}
